<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
<style>
  /* 面板部分 */
  /* 箭头样式 */
  .midate-prev-m,
  .midate-prev-y {
    position: relative;
    display: inline-block;
    cursor: pointer;
    width: 0;
    height: 0;
    border-right: 10px solid #999;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
  }
  .midate-next-m,
  .midate-next-y {
    position: relative;
    display: inline-block;
    cursor: pointer;
    width: 0;
    height: 0;
    border-left: 10px solid #999;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
  }
  .midate-prev-y::before {
    position: absolute;
    content: '';
    width: 0;
    height: 0;
    left: -8px;
    top: -10px;
    border-right: 10px solid #999;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
  }
  .midate-next-y::after {
    position: absolute;
    content: '';
    width: 0;
    height: 0;
    right: -8px;
    top: -10px;
    border-left: 10px solid #999;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
  }
  .midate-now-y {
    width: 19px;
    text-align: center;
  }
  /* 主体样式 */
  .midate-wrapper {
    z-index: 66666666;
    background-color: #fff;
    position: absolute;
    width: 270px;
    border: solid 1px #ddd;
    border-radius: 2px;
    box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
    color: #333;
  }
  /* 头部样式 */
  .midate-header {
    display: flex;
    justify-content: space-between;
    padding: 8px 24px;
    line-height: 18px;
    border-bottom: solid 1px #ddd;
  }
  /* 星期样式 */
  .midate-week-line {
    display: flex;
    justify-content: space-around;
  }
  .midate-week-line,
  .midate-date-wrap {
    user-select: none;
    padding: 8px 12px;
  }
  .midate-date-wrap {
    padding-top: 0;
    border-bottom: solid 1px #ddd;
  }
  .midate-week-item,
  .midate-date-item {
    display: inline-block;
    width: 30px;
    height: 30px;
    line-height: 30px;
    text-align: center;
  }
  /* 日期样式 */
  .midate-date-line {
    display: flex;
    justify-content: space-around;
  }
  .midate-date-item {
    cursor: pointer;
  }
  .midate-date-item:hover {
    color: #000;
    background-color: #eee;
  }
  .midate-day-prev,
  .midate-day-next {
    color: #d2d2d2;
  }
  /* 时间输入区域 */
  .midate-time {
    display: flex;
    padding: 8px 0 0 4px;
  }
  .midate-time-inputs input{
    font-size: 13px;
    width: 32px;
    margin-right: 4px;
    border-radius: 5px;
    border: solid 1px #666;
    outline: none;
  }
  /* 按钮样式 */
  .midate-btns {
    display: flex;
    justify-content: flex-end;
    padding: 8px;
  }
  .midate-btns span {
    font-size: 14px;
    border: solid 1px #ccc;
    padding: 2px 8px;
    cursor: pointer;
  }
</style>
</head>
<body>
  <div class="midate-wrapper">
    <div class="midate-header">
      <span class="midate-prev-y"></span>
      <span id="preMonth" class="midate-prev-m"></span>
      <span id="nowYear"></span>年
      <span id="nowMonth" class="midate-now-y"></span>月
      <!-- <span id="nowDate"></span> -->
      <span id="nextMonth" class="midate-next-m"></span>
      <span class="midate-next-y"></span>
    </div>
    <div id="midate-weekLine" class="midate-week-line"></div>
    <div id="midate-dateWrap" class="midate-date-wrap"></div>
    <div class="midate-time">
      <div class="midate-time-inputs">
        <input type="number" value="0" min="0" max="23" onfocus="event.target.select();" onkeypress="if(this.value.length<2||window.getSelection().toString()!=''){return event.keyCode>=48&&event.keyCode<=57}else{return false}" onblur="if(this.value*1>this.max*1){this.value = this.max*1}else{this.value = this.value*1}">时
        <input type="number" value="0" min="0" max="59" onfocus="event.target.select();" onkeypress="if(this.value.length<2||window.getSelection().toString()!=''){return event.keyCode>=48&&event.keyCode<=57}else{return false}" onblur="if(this.value*1>this.max*1){this.value = this.max*1}else{this.value = this.value*1}">分
        <input type="number" value="0" min="0" max="59" onfocus="event.target.select();" onkeypress="if(this.value.length<2||window.getSelection().toString()!=''){return event.keyCode>=48&&event.keyCode<=57}else{return false}" onblur="if(this.value*1>this.max*1){this.value = this.max*1}else{this.value = this.value*1}">秒
      </div>
    </div>
    <div class="midate-btns">
      <span class="midate-btn-clear">重置</span>
      <span class="midate-btn-now">现在</span>
      <span class="midate-btn-confirm">确定</span>
    </div>
  </div>
  <input id="ll" type="text" value="66">
</body>
<script>
  for(let i = 0;i<60;i++){
    console.log(`<option value="${i}">${i}</option>\n`)
  }
  var ll = document.getElementById('ll');
  console.log("ll:",ll)
  // ll.on('click', function() {
  //   console.log("监听点击事件")
  // }).on('focus', function() {
  //   console.log("监听聚焦")
  // }).on('blur', function() {
  //   console.log("监听聚焦")
  // })
  // 工具方法 - start
  // 1.为了获得每个月的日期有多少，我们需要判断 平年闰年[四年一闰，百年不闰，四百年再闰]
  const isLeapYear = (year) => {
    return (year % 400 === 0) || (year % 100 !== 0 && year % 4 === 0);
  };
  // 2.获得每个月的日期有多少，注意 month - [0-11]
  const getMonthCount = (year, month) => {
    let arr = [
      31, null, 31, 30, 
      31, 30, 31, 31,
      30, 31, 30, 31
    ];
    let count = arr[month] || (isLeapYear(year) ? 29 : 28);
    return Array.from(new Array(count), (item, index) => index + 1);
  };
  // 3.获得某年某月的 1号 是星期几，这里要注意的是 JS 的 API-getDay() 是从 [日-六](0-6)，返回 number
  const getWeekday = (year, month) => {
    let date = new Date(year, month, 1);
    return date.getDay();
  };
  // 获得第一行上个月天数占据多少个
  const getPreMonthDaysByWeekStart = (year, month, weekStart) => {
    return getWeekday(year, month) >= weekStart ? getWeekday(year, month) - weekStart : getWeekday(year, month) + 7 - weekStart
  }
  // 4.获得上个月的天数
  const getPreMonthCount = (year, month) => {
    if (month === 0) {
      return getMonthCount(year - 1, 11);
    } else {
      return getMonthCount(year, month - 1);
    }
  };
  // 5.获得下个月的天数
  const getNextMonthCount = (year, month) => {
    if (month === 11) {
      return getMonthCount(year + 1, 0);
    } else {
      return getMonthCount(year, month + 1);
    }
  };
  // 6.生成日历表头
  function getCalendarTitle(weekStart) {
    weekStart = /^[0-6]$/.test(weekStart) == false ? 0 : weekStart;
    let weekArr = '日一二三四五六'.split('');
    let week1 = weekArr.slice(0, weekStart);
    let week2 = weekArr.slice(weekStart);
    return week2.concat(week1).join('');
  }
  // 工具方法 - end
  let weekStart = 1;
  let weekStr = getCalendarTitle(weekStart);
  weekArr = weekStr.split('').map(item => '' + item);
  // 插入星期 dom
  let weekDomStr = '';
  let oFragWeek = document.createDocumentFragment();
  weekArr.forEach(item => {
    let oSpan = document.createElement('span');
    let oText = document.createTextNode(item);
    oSpan.appendChild(oText);
    oSpan.classList.add('midate-week-item');
    oFragWeek.appendChild(oSpan);
  });
  let weekWrap = document.getElementById('midate-weekLine');
  weekWrap.appendChild(oFragWeek);

  // 这里获得我们第一次的 数据 数组
  const updateCalendar = (year, month) => {
    if (typeof year === 'undefined' && typeof month === 'undefined') {
      let nowDate = new Date();
      year = nowDate.getFullYear();
      month = nowDate.getMonth();
      // day = nowDate.getDate();
    }
    // 更新一下顶部的年月显示
    document.getElementById('nowYear').innerHTML = year;
    document.getElementById('nowMonth').innerHTML = month + 1;
    // document.getElementById('nowDate').innerHTML = day;
    // 生成日历数据，上个月剩下的的 x 天 + 当月的 28（平年的2月）或者29（闰年的2月）或者30或者31天 + 下个月的 y 天 = 42
    let monthIndex = month; // 当前月
    let dayIndex; // 当前天
    let ymd; // 保存年月日
    let res = [];
    let currentMonth = getMonthCount(year, month);
    let preMonth = getPreMonthCount(year, month);
    let nextMonth = getNextMonthCount(year, month);
    let PreMonthDays = getPreMonthDaysByWeekStart(year, month, weekStart);
    if (PreMonthDays == 0) {
      PreMonthDays = -preMonth.length
    }
    // 感谢网友 luoyiming 的测试（哈哈！谢谢！）：这里当 PreMonthDays 为 0 的时候会截取上月的所有数据
    let preArr = preMonth.slice(-1 * PreMonthDays)
    let nextArr = nextMonth.slice(0, 42 - currentMonth.length - PreMonthDays);
    console.log("currentMonth:",currentMonth,",preMonth:",preMonth,",nextMonth:",nextMonth)
    console.log("PreMonthDays:",PreMonthDays)
    console.log(",preArr:",preArr,",currentMonth:",currentMonth,",nextArr:",nextArr)
    res = [].concat(preArr, currentMonth, nextArr);
    // 上面经过我本人的测试是没有什么问题，接下来就是更新 dom 的信息的问题
    let hadDom = document.getElementsByClassName('midate-date-item');
    if (hadDom && hadDom.length) {
      let domArr = document.getElementsByClassName('midate-date-item');
      for (let i = 0; i < domArr.length; i++) {
        dayIndex = res.shift();
        domArr[i].innerHTML = dayIndex;
        if (i+1 <= preArr.length) {
          domArr[i].className = 'midate-date-item midate-day-prev'
        } else if (i+1 > (preArr.length + currentMonth.length)) {
          domArr[i].className = 'midate-date-item midate-day-next'
         } else {
          domArr[i].className = 'midate-date-item'
         }
         domArr[i].className == 'midate-date-item midate-day-prev' ? (monthIndex = month) : domArr[i].className == 'midate-date-item' ? (monthIndex = month + 1) : (monthIndex = month + 2);
         ymd = (year < 1000 ? ('0' + year) : year < 100 ? ('00' + year) : year < 10 ? ('000' + year) : year) + "-" + (monthIndex < 10 ? ('0'+monthIndex) : monthIndex) + "-" + (dayIndex < 10 ? ('0'+dayIndex) : dayIndex);
         domArr[i].setAttribute('mi-ymd', ymd)
      }
    } else {
      // 如果之前没有结构的话
      let str = '';
      let className = 'midate-date-item';
      for (let i = 0; i < 6; i++) {
        str += '<div class="midate-date-line">';
        for (let j = 0; j < 7; j++) {
          className = ((i*7) + (j+1)) <= preArr.length ? 'midate-date-item midate-day-prev' : ((i*7) + (j+1)) > (preArr.length + currentMonth.length) ? 'midate-date-item midate-day-next' : 'midate-date-item'
          monthIndex = ((i*7) + (j+1)) <= preArr.length ? month : ((i*7) + (j+1)) > (preArr.length + currentMonth.length) ? (month + 2) : (month + 1)
          dayIndex = res.shift();
          ymd = (year < 1000 ? ('0' + year) : year < 100 ? ('00' + year) : year < 10 ? ('000' + year) : year) + "-" + (monthIndex < 10 ? ('0'+monthIndex) : monthIndex) + "-" + (dayIndex < 10 ? ('0'+dayIndex) : dayIndex)
          str += `<span class='${className}' mi-ymd='${ymd}'>${dayIndex}</span>`;
          if (j === 6) {
            str += '</div>';
          }
        }
      }
      document.getElementById('midate-dateWrap').innerHTML = str;
    }
  };

  updateCalendar();
  // 添加上一月，下一月事件
  let oPreButton = document.getElementById('preMonth');
  let oNextButton = document.getElementById('nextMonth');
  oPreButton.addEventListener('click', function () {
    let currentYear = +document.getElementById('nowYear').textContent;
    let currentMonth = +document.getElementById('nowMonth').textContent - 1;
    if (currentMonth === 0) {
      updateCalendar(currentYear - 1, 11);
    } else {
      updateCalendar(currentYear, currentMonth - 1);
    }
  });
  oNextButton.addEventListener('click', function () {
    let currentYear = +document.getElementById('nowYear').textContent;
    let currentMonth = +document.getElementById('nowMonth').textContent - 1;
    if (currentMonth === 11) {
      updateCalendar(currentYear + 1, 0);
    } else {
      updateCalendar(currentYear, currentMonth + 1);
    }
  });
</script>
</html>